﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Transactions;



namespace BusinessComponents.Managers
{
    class ReservationMgr : IReservationMgr
    {
        private WaterFrontEntities wfe = new WaterFrontEntities();

        public ReservationMaster getReservationInfo(string reservationId)
        {
            if (reservationId == null || reservationId.Trim().Length == 0)
            {
                return null;
            }
            else
            {
                using (wfe = new WaterFrontEntities())
                {
                    var master = wfe.ReservationMasters.FirstOrDefault(m => m.ReservationId == reservationId.ToUpper());
                    if (master != null)
                    {
                        master.populate();
                    }
                    return master;
                }
            }
        }

        public bool isOwner(string reservationId, Guid userId)
        {
            using (wfe = new WaterFrontEntities())
            {
                var res = (from r in wfe.ReservationMasters
                           where r.ReservationId == reservationId && r.UserId == userId
                           select r).FirstOrDefault();

                return res != null;
            }
        }

        public bool createReservation(ReservationMaster master)
        {
            try
            {
                IEnumerable<Room> rooms = ManagerFactory.RoomMgr.FindAllActiveRoomsByType(master.TypeCode);
                using (wfe = new WaterFrontEntities())
                {
                    using (TransactionScope transaction = new TransactionScope())
                    {
                        int rmNum = master.RoomCount;
                        List<string> rms = new List<string>(rmNum);

                        foreach (Room r in rooms)
                        {
                            if (rmNum > 0)
                            {
                                if (isRoomReservable(r.RoomNo, master.StartDate, master.EndDate))
                                {
                                    rms.Add(r.RoomNo);
                                    rmNum--;
                                }
                            }
                            else
                            {
                                break;
                            }
                        }

                        if (rmNum > 0)
                        {
                            return false;
                        }
                        else
                        {
                            master.ReservationId = generateReservationNum();
                            master.CreatedDateTime = DateTime.Now;
                            wfe.AddToReservationMasters(master);
                            wfe.SaveChanges();

                            IEnumerable<DateTime> dates = getDateList(master.StartDate, master.EndDate);
                            foreach (string num in rms)
                            {
                                foreach (DateTime date in dates)
                                {
                                    ReservationDetail rd = new ReservationDetail();
                                    rd.ReservationId = master.ReservationId;
                                    rd.RoomNo = num;
                                    rd.DateReserved = date;
                                    wfe.AddToReservationDetails(rd);
                                }
                            }

                            wfe.SaveChanges();

                            transaction.Complete();
                        }
                    }

                    wfe.AcceptAllChanges();
                }

                return true;
            }
            catch(Exception ex)
            {
                string s = ex.StackTrace;
                return false;
            }

        }

        public void cancelReservation(string reservationId)
        {
            using (wfe = new WaterFrontEntities())
            {
                var master = wfe.ReservationMasters.FirstOrDefault(m => m.ReservationId == reservationId);
                if (master != null)
                {
                    using (TransactionScope transaction = new TransactionScope())
                    {
                        foreach (var detail in master.ReservationDetails.ToList())
                        {
                            wfe.DeleteObject(detail);
                        }

                        master.IsCancelled = 1;
                        master.CancelDateTime = DateTime.Now;
                        wfe.SaveChanges();

                        transaction.Complete();
                    }

                    wfe.AcceptAllChanges();
                }
            }
        }

        public IEnumerable<ReservationMaster> listReservationByUserId(Guid userId)
        {
            using (wfe = new WaterFrontEntities())
            {
                return (from m in wfe.ReservationMasters
                       where m.UserId == userId && m.IsCancelled == 0
                       orderby m.StartDate descending, m.CreatedDateTime descending
                       select m).ToList();
            }
        }

        public IEnumerable<ReservationMaster> listReservationByPattern(string pattern)
        {
            using (wfe = new WaterFrontEntities())
            {
                return (from m in wfe.ReservationMasters.Include("Customer")
                       where m.ReservationId.StartsWith(pattern)
                       orderby m.IsCancelled ascending, m.CreatedDateTime descending
                        select m).ToList();
            }
        }

        private string generateReservationNum()
        {
            string allowedChars = "ABCDEFGHJKLMNOPQRSTUVWXYZ0123456789";
            int length = 6;
            char[] chars = new char[length];
            string refNum = null;

            do{
                Random randNum = new Random();
                
                int allowedCharCount = allowedChars.Length;

                for (int i = 0; i < length; i++)
                {
                    chars[i] = allowedChars[(int)((allowedChars.Length) * randNum.NextDouble())];
                }

                refNum = new string(chars);
                var o = wfe.ReservationMasters.FirstOrDefault(m => m.ReservationId == refNum);
                if (o == null)
                {
                    break;
                }
            } while (true) ;

            return refNum;

        }

        private bool isRoomReservable(string roomNum, DateTime startDate, DateTime endDate)
        {
            try
            {
                using (WaterFrontEntities wf = new WaterFrontEntities())
                {
                    List<ReservationDetail> records = (from detail in wf.ReservationDetails
                                                       where detail.DateReserved >= startDate && detail.DateReserved <= endDate && detail.RoomNo == roomNum
                                                       select detail).ToList();


                    return (records == null || records.Count() == 0) ? true : false;
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private IEnumerable<DateTime> getDateList(DateTime startDate, DateTime endDate)
        {
            List<DateTime> dates = new List<DateTime>();

            do
            {
                dates.Add(startDate);
                startDate = startDate.AddDays(1);
            } 
            while (startDate <= endDate);

            return dates;
        }
    }
}
